//
//  JYJMusicOperation.m
//  HappyListen
//
//  Created by 冀永金 on 16/9/19.
//  Copyright © 2016年 冀永金. All rights reserved.
//

#import "JYJMusicOperation.h"
#import "JYJProgramModel.h"
#import <objc/runtime.h>
#define kKVOBlock(KEYPATH,BLOCK) \
[self willChangeValueForKey:KEYPATH]; \
BLOCK(); \
[self didChangeValueForKey:KEYPATH];

static NSTimeInterval kTimeoutInterval = 60.0;
@interface JYJMusicOperation () {
    BOOL _finished;
    BOOL _executing;//是否执行
}
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
@property (nonatomic, weak) NSURLSession *session;

@end
@implementation JYJMusicOperation
- (instancetype)initWithModel:(JYJProgramModel *)model session:(NSURLSession *)session {
    self = [super init];
    if (self) {
        self.model = model;
        self.session = session;
        [self stateRequest];
    }
    return self;
}

- (void)dealloc {
    self.task = nil;
}
-(void)setTask:(NSURLSessionDownloadTask *)task {
    [_task removeObserver:self forKeyPath:@"state"];
    if (_task != task) {
        _task = task;
    }
    if (task != nil) {
        [task addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
    }
}
- (void)configTask {
    self.task.jyj_programModel = self.model;
}
- (void)stateRequest {
    NSURL *url = [NSURL URLWithString:self.model.music_media];
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:kTimeoutInterval];
    self.task = [self.session downloadTaskWithRequest:request];
    [self configTask];
}

- (void)start {
    if (self.isCancelled) {
        kKVOBlock(@"isFinished", ^{
            _finished = YES;
        });
        return;
    }
    [self willChangeValueForKey:@"isExecuting"];
    if (self.model.resumeData) {
        [self resume];
    }else {
        [self.task resume];
        self.model.status = kJYJMusicStatusRunning;
    }
    _executing = YES;
    [self didChangeValueForKey:@"isExecuting"];
}
- (BOOL)isExecuting {
    return _executing;
}
- (BOOL)isFinished {
    return _finished;
}
// 并发
- (BOOL)isConcurrent {
    return YES;
}
- (void)suspend {
    if (self.task) {
        __weak __typeof(self) weakSelf = self;
        __block NSURLSessionDownloadTask *weakTask = self.task;
        [self willChangeValueForKey:@"isExecuting"];
        __block BOOL isExecuting = _executing;
        [self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
            weakSelf.model.resumeData = resumeData;
            weakTask = nil;
            isExecuting = NO;
            [weakSelf didChangeValueForKey:@"isExecuting"];
            dispatch_async(dispatch_get_main_queue(), ^{
                weakSelf.model.status = kJYJMusicStatusSuspended;
            });
        }];
        [self.task suspend];
    }
}
- (void)resume {
    if (self.model.status == kJYJMusicStatusCompleted) {
        return;
    }
    self.model.status = kJYJMusicStatusRunning;
    if (self.model.resumeData) {
        self.task = [self.session downloadTaskWithResumeData:self.model.resumeData];
        [self configTask];
    }else if (self.task == nil || (self.task.state == NSURLSessionTaskStateCompleted && self.model.progress < 1.0 )) {
        [self stateRequest];
    }
    [self willChangeValueForKey:@"isExecuting"];
    [self.task resume];
    _executing = YES;
    [self didChangeValueForKey:@"isExecuting"];
}
- (NSURLSessionDownloadTask *)downloadTask {
    return self.task;
}

- (void)cancel {
    [self willChangeValueForKey:@"isCancelled"];
    [super cancel];
    [self.task cancel];
    self.task = nil;
    [self didChangeValueForKey:@"isCancelled"];
    [self completeOperation];
}
- (void)completeOperation {
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];
    
    _executing = NO;
    _finished = YES;
    
    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
 
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"state"]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            switch (self.task.state) {
                case NSURLSessionTaskStateSuspended:{
                    self.model.status = kJYJMusicStatusSuspended;
                    break;
                }
                case NSURLSessionTaskStateCompleted:
                    if (self.model.progress >= 1.0) {
                        self.model.status = kJYJMusicStatusCompleted;
                    }else {
                        self.model.status = kJYJMusicStatusSuspended;
                    }
                
                default:
                    break;
            }
        });
    }
}
- (void)downloadFinished {
    [self completeOperation];
}




@end
static const void *h_jyj_musicModelKey = @"h_jyj_musicModelKey";
@implementation NSURLSessionTask (MusciModel)

- (void)setJyj_programModel:(JYJProgramModel *)jyj_programModel {
    objc_setAssociatedObject(self, h_jyj_musicModelKey, jyj_programModel, OBJC_ASSOCIATION_ASSIGN);
}
- (JYJProgramModel *)jyj_programModel {
    return objc_getAssociatedObject(self, h_jyj_musicModelKey);
}

@end


